FUNCTION MODULE ZSTB_RFC_DATASOURCE_SELECT
FUNCTION GROUP  ZSTB_FUNCTION_GROUP
DESCRIPTION     select data from data source
PROCESSING TYPE : remote-enable module

IMPORT
PARAMETER       |TYPE_SPEC|ASSOCIATED_TYPE        |DEFAULT|OPTIONAL|PASS_VALUE|DESCRIPTION          
----------------|---------|-----------------------|-------|--------|----------|---------------------
DATASOURCE      |LIKE     |ROOSOURCE-OLTPSOURCE   |       |NO      |YES       |dataSource to extract
FETCH_SIZE      |TYPE     |ZSTB_FETCH_SIZE_TYPE   |1024   |YES     |YES       |fetch size           
MAX_LINE_NUMBER |TYPE     |ZSTB_LINE_NUMBER_TYPE  |8192   |YES     |YES       |maximum line number  
UPDATE_MODE     |LIKE     |RSIODYNP4-UPDMODE      |'F'    |YES     |YES       |update mode          
FIELD_SEPARATOR |TYPE     |ZSTB_FIELD_SEP_TYPE    |','    |YES     |YES       |CSV field separator  
TARGET_SYSTEM   |LIKE     |RSIODYNP4-RLOGSYS      |       |YES     |YES       |target system        
SESSION_ID      |TYPE     |ZSTB_SESSION_ID_TYPE   |       |NO      |YES       |session ID           
STRING_DELIMITER|TYPE     |ZSTB_STRING_DELIM_TYPE |'"'    |YES     |YES       |CSV string delimiter 
REQUEST_UUID    |TYPE     |ZSTB_REQUEST_UUID_TYPE |       |NO      |YES       |request UUID         
USER_EXIT       |TYPE     |ZSTB_USER_EXIT_TYPE    |'X'    |YES     |YES       |user exit trigger    
ROW_SEPARATOR   |TYPE     |ZSTB_ROW_SEPARATOR_TYPE|'\r\n' |YES     |YES       |row separator        

EXPORT
PARAMETER       |TYPE_SPEC|ASSOCIATED_TYPE       |PASS_VALUE|DESCRIPTION         
----------------|---------|----------------------|----------|--------------------
MAX_FETCH_NUMBER|TYPE     |ZSTB_FETCH_NUMBER_TYPE|YES       |maximum fetch number

SOURCE CODE
...........
function zstb_rfc_datasource_select .
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(DATASOURCE) LIKE  ROOSOURCE-OLTPSOURCE
*"     VALUE(FETCH_SIZE) TYPE  ZSTB_FETCH_SIZE_TYPE DEFAULT 1024
*"     VALUE(MAX_LINE_NUMBER) TYPE  ZSTB_LINE_NUMBER_TYPE DEFAULT 8192
*"     VALUE(UPDATE_MODE) LIKE  RSIODYNP4-UPDMODE DEFAULT 'F'
*"     VALUE(FIELD_SEPARATOR) TYPE  ZSTB_FIELD_SEP_TYPE DEFAULT ','
*"     VALUE(TARGET_SYSTEM) LIKE  RSIODYNP4-RLOGSYS OPTIONAL
*"     VALUE(SESSION_ID) TYPE  ZSTB_SESSION_ID_TYPE
*"     VALUE(STRING_DELIMITER) TYPE  ZSTB_STRING_DELIM_TYPE DEFAULT '"'
*"     VALUE(REQUEST_UUID) TYPE  ZSTB_REQUEST_UUID_TYPE
*"     VALUE(USER_EXIT) TYPE  ZSTB_USER_EXIT_TYPE DEFAULT 'X'
*"     VALUE(ROW_SEPARATOR) TYPE  ZSTB_ROW_SEPARATOR_TYPE DEFAULT
*"       '\r\n'
*"  EXPORTING
*"     VALUE(MAX_FETCH_NUMBER) TYPE  ZSTB_FETCH_NUMBER_TYPE
*"----------------------------------------------------------------------

data: wa_source type roosource,
  numberfields type i,
  modulo type i,
  max_size type rsiodynp4-maxsize,
  max_fetch type rsiodynp4-calls,
  line_counter type i,
  fetch_number type i,
  line_number type i,
  wf_ref  type ref to data,
  l_s_roosgen type rsaot_s_roosgen,
  l_t_roosgen type rsaot_t_roosgen,
  l_tfstruc type sbiwm_structure,
  select type table of rsselect,
  fields type table of rsfieldsel.
field-symbols: <fs_tab> type standard table,
  <datarow> type any.

* create temporary in-memory table with the same structure as datasource
select single * into wa_source from roosource where oltpsource = datasource.
create data wf_ref type table of (wa_source-exstruct).
assign wf_ref->* to <fs_tab>.

* extract ds metadata (structure & field list)
* rsa1_single_oltpsource_get : internal function to get metadata about the ds
*                              see : https://www.se80.co.uk/sapfms/r/rsa1/rsa1_single_oltpsource_get.htm
*                              see : https://www.sapdatasheet.org/abap/func/rsa1_single_oltpsource_get.html
* l_t_roosgen : pointer to the metadata
* l_s_roosgen : temporary table to store the returned metadata
call function 'RSA1_SINGLE_OLTPSOURCE_GET'
  exporting
    i_oltpsource = datasource
  importing
    e_t_roosgen = l_t_roosgen.
read table l_t_roosgen into l_s_roosgen index 1.
* load ds structure regarding last returned metadata
* tfmethode  : type of structure (i for idoc ; ¿ t for table ?)
*              warning : i did not yet find information about rsaot_s_roosgen
* l_tfstruc : store ds structure description
case l_s_roosgen-tfmethode.
  when 'i'.
    l_tfstruc = l_s_roosgen-tfstridoc.
  when 't'.
    l_tfstruc = l_s_roosgen-tfstruc.
endcase.
* get field list about ds
* fill_field_list : internal sub-routine to extract field list
* saplrsap : internal sap function about data transfert
*            see : https://www.sapdatasheet.org/abap/prog/saplrsap.html
* fields : table to store ds fields list
perform fill_field_list(saplrsap) tables fields using l_tfstruc.

* extract ds data
* rsfh_get_data_simple : internal sap function to get data from ds
*                        see : https://www.se80.co.uk/sapfms/r/rsfh/rsfh_get_data_simple.htm
*                        see : https://www.sapdatasheet.org/abap/func/rsfh_get_data_simple.html
* i_t_select : is supposed to be selection criteria (like where in sql)
*              but whatever we set in, output is always on all ds fields
* i_t_field : is supposed to be filter fields list to keep in output
*             but whatever we set in, output is always on all ds fields
max_size = fetch_size.
max_fetch = trunc( max_line_number / fetch_size ).
modulo = max_line_number mod fetch_size.
if modulo <> 0.
  max_fetch = max_fetch + 1.
endif.

* load DS asynchronously IMplicitly in user exit ZXRSAU01
if user_exit <> ''. " test 'is initial' fail ! why ???
* export variables to use in user exit
  export session_id to memory id 'ZSTB_SESSION_ID'.
  export request_uuid to memory id 'ZSTB_REQUEST_UUID'.
  export field_separator to memory id 'ZSTB_FIELD_SEPARATOR'.
  export string_delimiter to memory id 'ZSTB_STRING_DELIMITER'.
  export max_line_number to memory id 'ZSTB_MAX_LINE_NUMBER'.
  export row_separator to memory id 'ZSTB_ROW_SEPARATOR'.
* extract DS IMplicitly in user exit
  call function 'RSFH_GET_DATA_SIMPLE'
    exporting
      i_requnr = 'semarchy'
      i_osource = datasource
      i_maxsize = max_size
      i_maxfetch = max_fetch
      i_updmode = update_mode
      i_rlogsys = target_system
      i_quiet = '1' " comment to see loaded line number in a pop-up (ie for debug)
    tables
      i_t_select = select
      i_t_field = fields
*     NO TABLE TO LOAD
    exceptions
      generation_error = 1
      interface_table_error = 2
      metadata_error = 3
      no_authority = 4
      others = 5.
* catch exception
  if sy-subrc <> 0.
    case sy-subrc.
      when '1' or '2' or '3' or '4'.
        message id sy-msgid type 'i' number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      when others.
        message id sy-msgid type 'i' number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endcase.
  endif.
* WARNING : i did not succed to return maximum fetch number in memory
*  import max_fetch_number from memory id 'ZSTB_MAX_FETCH_NUMBER'.
  max_fetch_number = max_fetch.
* free variables used in user exit
  free memory id 'ZSTB_SESSION_ID'.
  free memory id 'ZSTB_REQUEST_UUID'.
  free memory id 'ZSTB_FIELD_SEPARATOR'.
  free memory id 'ZSTB_STRING_DELIMITER'.
  free memory id 'ZSTB_MAX_LINE_NUMBER'.
  free memory id 'ZSTB_ROW_SEPARATOR'.
*  free memory id 'ZSTB_MAX_FETCH_NUMBER'.
* load DS synchronously EXplicitly in <fs_tab> table
else.
* extract DS
  call function 'RSFH_GET_DATA_SIMPLE'
    exporting
      i_requnr = 'semarchy'
      i_osource = datasource
      i_maxsize = max_size
      i_maxfetch = max_fetch
      i_updmode = update_mode
      i_rlogsys = target_system
      i_quiet = '1' " comment to see loaded line number in a pop-up (ie for debug)
    tables
      i_t_select = select
      i_t_field = fields
      e_t_data = <fs_tab>
    exceptions
      generation_error = 1
      interface_table_error = 2
      metadata_error = 3
      no_authority = 4
      others = 5.

* catch exception
  if sy-subrc <> 0.
    case sy-subrc.
      when '1' or '2' or '3' or '4'.
        message id sy-msgid type 'i' number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      when others.
        message id sy-msgid type 'i' number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endcase.
  endif.

* load temporary table
  call function 'ZSTB_COUNT_NUMBER_FIELDS'
    importing
      numberfields = numberfields
    tables
      table_to_count = <fs_tab>.
* load temporary table
* TODO : before filling transfert table, apply filters to :
* - select only the fields we want, like select ... in sql or fields in zstb_rfc_sql_select
* - select only the fields we want, like where ... in sql or whereclause in zstb_rfc_sql_select
  fetch_number = 0.
  line_number = 0.
  line_counter = 0.
  loop at <fs_tab> assigning <datarow>.
* insert into transfert table
    call function 'ZSTB_INSERT_TRANSF_TBL'
      exporting
        numberfields = numberfields
        datarow = <datarow>
        string_delimiter = string_delimiter
        field_separator = field_separator
        row_separator = row_separator
        session_id = session_id
        request_uuid = request_uuid
        fetch_number = fetch_number
        line_number = line_number.
*   next line
    line_counter = line_counter + 1.
    check line_counter < max_line_number.
    line_number = line_number + 1.
    if line_number = fetch_size.
      fetch_number = fetch_number + 1.
      line_number = 0.
    endif.
  endloop.

* return maximum fetch number
  max_fetch_number = fetch_number.

* free memory
  call function 'ZSTB_FREE_DS_MEMORY'.

endif.

endfunction.